﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace SqlInjectionValidator
{
	class Program
	{
		static void Main(string[] args)
		{
			RunLocalTest(CommaInjection);
			RunLocalTest(SafeQuery);
			RunLocalTest(QueryStatckingInjection);
			RunLocalTest(PerformanceTest);
			Console.ReadLine();
		}

		private static void RunLocalTest(Action action)
		{
			try
			{
				action();
				Console.WriteLine("Test {0} succeeded.", action.Method);
			}
			catch (Exception ex)
			{
				Console.WriteLine("Test {0} Failed : {1}", action.Method, ex);
			}
		}

		private static void SafeQuery()
		{
			Assert.AreEqual(ValidationResult.NoInjectionFound,
				ValidateQuery(@"Select stuff from soewhere safe (HAAKJSHD)")
				);
			Assert.AreEqual(ValidationResult.NoInjectionFound,
				ValidateQuery(@"Select stuff from soewhere safe (HAAKJSHD) but '/*Some Literal' that looks like comment")
				);
			Assert.AreEqual(ValidationResult.NoInjectionFound,
				ValidateQuery(@"Select stuff from soewhere safe (HAAKJSHD) but '--Some Literal' that looks like comment")
				);
			Assert.AreEqual(ValidationResult.NoInjectionFound,
					ValidateQuery(@"Select stuff from soewhere safe where a = ' /* then '' union ' and b = '/*Some Literal' + 'that looks like comment'")
				);
			Assert.AreEqual(ValidationResult.NoInjectionFound,
					ValidateQuery(@"Select stuff from soewhere safe
where [a;b] = ' /* then '' union ' and [b/*c] = '/*Some Literal' + 'that looks like comment'")
				);
			Assert.AreEqual(
				ValidationResult.NoInjectionFound,
				ValidateQuery(
					@"
SELECT * FROM USERS WHER id = 2; UPDATE STATISTICS USERS
", 2
					)
				);
		}

		private static ValidationResult ValidateQuery(string query, int? stacks = 1, int? unioins = null)
		{
			return SqlInjectionValidator.ValidateQueryFast(query, stacks, unioins);
		}

		private static void CommaInjection()
		{
			Assert.AreEqual(
				ValidationResult.Comment,
				ValidateQuery(@"SELECT STUFF from Where I shouldn't' /* some Comment *."));
			Assert.AreEqual(
				ValidationResult.Comment,
				ValidateQuery(@"SELECT STUFF '' from Where I-- shouldn't' /* some Comment *."));
		}

		private static void QueryStatckingInjection()
		{
			Assert.AreEqual(
				ValidationResult.Stacking,
				ValidateQuery(@"
SELECT * FROM Users WHERE id = 2; drop table [Important table]
")
				);
			Assert.AreEqual(
				ValidationResult.Stacking,
				ValidateQuery(@"
SELECT * FROM USERS WHER id = 2; UPDATE STATISTICS USERS
; drop table [Important Table]
", 2
				)
				);
		}

		private static void PerformanceTest()
		{
			var bigQuery = String.Join(" <NewQUery/> ",
						Enumerable.Repeat(
							@"
SELECT * FROM Users WHER [User name] = @@UserName and Password LIKE '%Passowrd%' and Dmoain = ''
",
							100000));
			var indexOftimer = Stopwatch.StartNew();
			var dest = new char[bigQuery.Length];
			bigQuery.CopyTo(0, dest, 0, bigQuery.Count());
			indexOftimer.Stop();
			Console.WriteLine("Minimum time to copy the big query is {0} ms", indexOftimer.ElapsedMilliseconds);

			var timer = Stopwatch.StartNew();
			ValidateQuery(bigQuery);
			timer.Stop();
			Console.WriteLine("Time Elapsed {0} ms for query as large as {1} charachters", timer.ElapsedMilliseconds, bigQuery.Length);
			Assert.IsTrue(timer.ElapsedMilliseconds < indexOftimer.ElapsedMilliseconds * 50);
		}
	}
}
